/**
 * Author: Zane
 * Email: 873934580@qq.com
 * Date: 2023/5/2
 */
import type { anyObj } from '@/types'
import type { RouteRecordName } from 'vue-router'
import type { IPermissionTree } from '@/model'
import type { IMenu } from '@/store/useMenu'
import router, { layout, DEFAULT_ROUTE_PREFIX } from '@/routers'
import { error } from '@/utils/index'
import { isNavigationFailure, NavigationFailureType } from 'vue-router'
import { useMenu } from '@/store/useMenu'

/**
 * 根据权限动态处理路由信息
 * @param rules
 */
export const handleRouter = (rules: IPermissionTree[]) => {
    const viewComponents = import.meta.glob('/src/pages/**/*.vue')
    const menu = addRouteItem(rules, viewComponents, layout.name!)

    useMenu().setMenu(menu)
}

/**
 * 动态添加路由信息
 * @param rules
 * @param components
 * @param parentName
 */
const addRouteItem = (rules: IPermissionTree[], components: anyObj, parentName: RouteRecordName) => {
    const menu: IMenu[] = []
    for (let rule of rules) {
        const m = handleMenu(rule)
        let children: IMenu[] = []
        if (!!rule.children && rule.children!.length > 0) {
            children = addRouteItem(rule.children!, components, parentName)
        }
        if (m) {
            m.children = children
            menu.push(m)
        }
        if (rule.type !== 'nav') continue
        const component = components[replenishComponentPath(rule.component!)]
        if (component) {
            router.addRoute(parentName, {
                path: normalizePath(rule.route!)!,
                name: rule.name!,
                component: component,
                meta: { title: rule.title },
            })
        } else {
            console.error(`【${rule.title}】未匹配到组件: [${rule.component}]`)
        }
    }
    return menu
}

const handleMenu: any = (rule: IPermissionTree) => {
    if (rule.type === 'btn' || rule.is_nav !== 1) return
    let r = rule.route ?? ''
    let isHttp = r.slice(0, 4) === 'http'

    return {
        title: rule.title,
        icon: rule?.icon,
        path: normalizePath(rule.route),
        externalLinks: isHttp,
        name: rule.name,
        children: undefined,
    }
}

const normalizePath = (path?: string) => {
    if (!path) return path
    if (path.slice(0, 4) === 'http') return path
    if (path[0] !== '/') path = '/' + path
    if (path.slice(0, 6) !== `/${DEFAULT_ROUTE_PREFIX}`) path = `/${DEFAULT_ROUTE_PREFIX}` + path
    return path
}

/**
 * 处理菜单目录
 * @param rules
 * @param pathPrefix
 */
const handleMenu1 = (rules: IPermissionTree[], pathPrefix = '/') => {
    const menu: any[] = []
    for (let index in rules) {
        // 按钮和设置为不展示为导航的菜单跳过
        if (rules[index].type === 'btn' || rules[index].is_nav === 0) {
            continue
        }
        let temp = {
            title: rules[index].title,
            icon: rules[index]?.icon,
            path: pathPrefix + rules[index].route,
            name: rules[index].name,
            children: [],
        }
        if (!!rules[index].children && rules[index].children!.length > 0) {
            temp.children = handleMenu1(rules[index].children!, pathPrefix) as any
        }

        menu.push(temp)
    }

    return menu
}

/**
 * 补充组件路径
 * @param path
 */
const replenishComponentPath = (path: string) => {
    if (path[0] === '/') {
        path = path.slice(1, path.length)
    }
    return `/src/pages/${path}`
}

/**
 * 根据路由名称push
 * @param name
 * @param param
 */
export const routeNamePush = async (name: string, param: anyObj = {}) => {
    return await routePush(name, param)
}

/**
 * 根据路由路径push
 * @param path
 */
export const routePathPush = async (path: string) => {
    return await routePush('', {}, path)
}

/**
 * 路由push
 * @param name
 * @param param
 * @param path
 */
export const routePush = async (name: string, param: anyObj = {}, path: string = '') => {
    try {
        const failure = await router.push(name ? { name: name, params: param } : { path: path })
        if (isNavigationFailure(failure, NavigationFailureType.aborted)) {
            error('导航失败，导航守卫被拦截！')
            return false
        } else if (isNavigationFailure(failure, NavigationFailureType.duplicated)) {
            error('导航失败，它位于导航目标位置！')
            return false
        }
    } catch (e) {
        error('导航失败，路由无效')
        return false
    }

    return true
}
